package com.cmict.data.infra.service.message;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.cmict.data.framework.common.pojo.PageResult;
import com.cmict.data.framework.tenant.core.context.TenantContextHolder;
import com.cmict.data.infra.controller.admin.message.vo.*;
import com.cmict.data.infra.convert.message.AnnouncementConverter;
import com.cmict.data.infra.convert.message.UserAnnouncementConverter;
import com.cmict.data.infra.dal.dataobject.message.Announcement;
import com.cmict.data.infra.dal.dataobject.message.UserAnnouncement;
import com.cmict.data.infra.dal.mysql.message.AnnouncementMapper;
import com.cmict.data.infra.dal.mysql.message.UserAnnouncementMapper;
import com.cmict.data.infra.enums.message.UserAnnouncementStateEnum;
import com.cmict.data.system.api.message.WsMessageDTO;
import com.cmict.data.system.api.user.AdminUserApi;
import com.cmict.data.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.cmict.data.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cmict.data.infra.enums.message.ErrorCodeConstants.NOTICE_NOT_FOUND;

/**
 * 用户公告表
 *
 * @author hccake 2020-12-25 08:04:53
 */
@Service
@Slf4j
public class UserAnnouncementServiceImpl extends ServiceImpl<UserAnnouncementMapper, UserAnnouncement>
        implements UserAnnouncementService {

    @Resource
    private AnnouncementMapper announcementMapper;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
//    @Resource
//    WebSocketSessionStore webSocketSessionStore;
//    @Resource
//    MessageDistributor messageDistributor;

    /**
     * 根据QueryObject查询分页数据
     *
     * @return PageResult<UserAnnouncementVO> 分页数据
     */
    @Override
    public PageResult<UserAnnouncementPageVO> queryPage(UserAnnouncementQO qo) {
        PageResult<UserAnnouncement> pageResult = baseMapper.queryPage(qo);
        PageResult<UserAnnouncementPageVO> result = UserAnnouncementConverter.INSTANCE.poToPageVoList(pageResult);
        result.getList().forEach(userAnnouncementPageVO -> {
//            userAnnouncementPageVO.setUsername(adminUserApi.getUser(userAnnouncementPageVO.getUserId()).getUsername());
            userAnnouncementPageVO.setContentDisplay(announcementMapper.selectOne("id",userAnnouncementPageVO.getAnnouncementId()).getContentDisplay());
            userAnnouncementPageVO.setCreateTime(announcementMapper.selectOne("id", userAnnouncementPageVO.getAnnouncementId()).getSendTime());
        });
        return result;
    }

    /**
     * 根据QueryObject查询分页数据
     *
     * @return PageResult<UserAnnouncementVO> 分页数据
     */
    @Override
    public PageResult<UserAnnouncementPageVO> templatePage(UserAnnouncementQO qo) {

        String sql = "select na.id from `notify_user_announcement`  nu inner  join `notify_announcement` na on nu.`announcement_id`=na.`id` where na.`template_id` = " + qo.getTemplateId() + "  and nu.send_deleted = 0;";
        List<Long> idList = baseMapper.getIdListByTemplate(sql);
        if(idList.size()<1){
            idList = new ArrayList<>();
            idList.add(0L);
        }
        qo.setIdList(idList);
            PageResult<UserAnnouncement> pageResult = baseMapper.queryTemplatePage(qo);
            PageResult<UserAnnouncementPageVO> result = UserAnnouncementConverter.INSTANCE.poToPageVoList(pageResult);
            if (result.getList() != null && result.getList().size() > 0) {
                result.getList().forEach(userAnnouncementPageVO -> {
                    Announcement announcement = announcementMapper.selectOne("id", userAnnouncementPageVO.getAnnouncementId());
                    if(announcement !=null){
                        userAnnouncementPageVO.setContentDisplay(announcementMapper.selectOne("id", userAnnouncementPageVO.getAnnouncementId()).getContentDisplay());
                        userAnnouncementPageVO.setCreateTime(announcementMapper.selectOne("id", userAnnouncementPageVO.getAnnouncementId()).getSendTime());
                    }
                });
            }


        return result;






    }

    @Override
    public Boolean removeSendDetail(Long id) {
        UserAnnouncement userAnnouncement = checkExit(id);
        userAnnouncement.setSendDeleted(true);
        int i = baseMapper.updateById(userAnnouncement);
        return SqlHelper.retBool(i);
    }

    public UserAnnouncement checkExit(Long id) {
        UserAnnouncement userAnnouncement = baseMapper.selectById(id);
        if (userAnnouncement == null) {
            throw exception(NOTICE_NOT_FOUND);
        }
        return userAnnouncement;
    }

    /**
     * 根据用户ID和公告id初始化一个新的用户公告关联对象
     *
     * @param userId         用户ID
     * @param announcementId 公告ID
     * @return UserAnnouncement
     */
    @Override
    public UserAnnouncement prodUserAnnouncement(Long userId, String username, Long announcementId) {
        UserAnnouncement userAnnouncement = new UserAnnouncement();
        userAnnouncement.setUserId(userId);
        userAnnouncement.setUsername(username);
        userAnnouncement.setAnnouncementId(announcementId);
        userAnnouncement.setReadTime(LocalDateTime.now());
        userAnnouncement.setCreateTime(LocalDateTime.now());
        userAnnouncement.setState(UserAnnouncementStateEnum.UNREAD.getValue());
        return userAnnouncement;
    }

    /**
     * 对用户公告进行已读标记
     *
     * @param userId         用户id
     * @param announcementId 公告id
     */
    @Override
    public void readAnnouncement(Long userId, List<Long> announcementId) {
        baseMapper.updateToReadState(userId, announcementId);
        executeMessageClock(String.valueOf(userId));
    }

    @Override
    public void prodUserAnnouncement(List<AdminUserRespDTO> userList, Long announcementId) {
        List<UserAnnouncement> userAnnouncements = new ArrayList<>(userList.size());
        for (AdminUserRespDTO user : userList) {
            Long userId = user.getId();
            UserAnnouncement userAnnouncement = prodUserAnnouncement(userId,user.getUsername(),
                    announcementId);
            userAnnouncements.add(userAnnouncement);
        }
        this.saveBatch(userAnnouncements);
        if(userAnnouncements.size()>0){
//            Long tenantId = TenantContextHolder.getTenantId();
//            if(tenantId == null){
                String sql  = "UPDATE `notify_user_announcement` SET tenant_id =  ( SELECT tenant_id FROM `notify_announcement` WHERE id = "+ announcementId +" ) WHERE  announcement_id = " + announcementId;
                baseMapper.updateTenantIdByAnnouncementId(sql);
//            }

        }



    }

    @Override
    public Boolean removeId(Long id) {
        UserAnnouncement userAnnouncement = checkExit(id);
        userAnnouncement.setRecDeleted(true);
        int i = baseMapper.updateById(userAnnouncement);
        return SqlHelper.retBool(i);
    }

    @Override
    public PageResult<MyAnnouncementPageVO> queryMyAnnouncePage(UserAnnouncementQO qo) {
        //TODO 代码需要整理，连表查询
        List<UserAnnouncement> userAnnouncements = baseMapper.selectListByUserIds(qo);
        List<Long> announcementId = userAnnouncements.stream().map(UserAnnouncement::getAnnouncementId).collect(Collectors.toList());
        AnnouncementQO announcementQO = new AnnouncementQO();
        BeanUtils.copyProperties(qo, announcementQO);
        announcementQO.setAnnouncementIds(announcementId);
        PageResult<Announcement> announcementPageResult = announcementMapper.queryPageForUser(announcementQO);
        PageResult<MyAnnouncementPageVO> myAnnouncementPageVOPageResult = AnnouncementConverter.INSTANCE.pageToPageVoList(announcementPageResult);

        Map<Long, UserAnnouncement> map = userAnnouncements.stream().collect(Collectors.toMap(UserAnnouncement::getAnnouncementId, userAnnouncement -> userAnnouncement));

        if(myAnnouncementPageVOPageResult.getList() !=null){
            myAnnouncementPageVOPageResult.getList().stream().forEach(myAnnouncementPageVO -> {
                myAnnouncementPageVO.setState(map.get(myAnnouncementPageVO.getId()).getState());
                myAnnouncementPageVO.setUserAnnouncementId(map.get(myAnnouncementPageVO.getId()).getId());
            });
        }
        return myAnnouncementPageVOPageResult;
    }

    @Override
    public Map<String,Object> getRemind(UserAnnouncementQO qo) {
        qo.setPageNo(1);
        qo.setPageSize(10);
        Map<String, Object> resultMap = new HashMap<>();
        boolean flag = true;
        for (int i = 0; i < 2; i++) {
            qo.setState(0); // false 未读  第一次获取普通消息
            List<UserAnnouncement> userAnnouncements = baseMapper.selecRemindListByUserIds(qo);
            List<Long> announcementId = userAnnouncements.stream().map(UserAnnouncement::getAnnouncementId).collect(Collectors.toList());
            AnnouncementQO announcementQO = new AnnouncementQO();
            BeanUtils.copyProperties(qo, announcementQO);
            announcementQO.setAnnouncementIds(announcementId);
            List<Integer> list = new ArrayList<>();
            if(flag){
                list.add(1);
                list.add(2);
                list.add(3);
                list.add(4);
                announcementQO.setTypes(list);
            }else{
                list.add(0);
                announcementQO.setTypes(list);
            }

            announcementQO.setStatus("1");
            PageResult<Announcement> announcementPageResult = announcementMapper.queryRemindPageForUser(announcementQO);
            PageResult<MyAnnouncementPageVO> myAnnouncementPageVOPageResult = AnnouncementConverter.INSTANCE.pageToPageVoList(announcementPageResult);
            if(userAnnouncements.size() > 0){
                Map<Long, UserAnnouncement> map = userAnnouncements.stream().collect(Collectors.toMap(UserAnnouncement::getAnnouncementId, userAnnouncement -> userAnnouncement));
                myAnnouncementPageVOPageResult.getList().stream().forEach(myAnnouncementPageVO -> {
                    myAnnouncementPageVO.setState(map.get(myAnnouncementPageVO.getId()).getState());
                    myAnnouncementPageVO.setUserAnnouncementId(map.get(myAnnouncementPageVO.getId()).getId());
                });
            }


            if(flag){
                resultMap.put("ordinaryMessage",myAnnouncementPageVOPageResult.getList());
            }else{
                // 普通消息
                resultMap.put("systemMessage",myAnnouncementPageVOPageResult.getList());
            }
            flag = false;

        }


        return resultMap;
    }
    @Override
    public Boolean removeByIds(List<Long> ids) {
        UserAnnouncement userAnnouncement = new UserAnnouncement().setRecDeleted(true);
        return baseMapper.updateByIds(userAnnouncement, ids);
    }

    @Override
    public long executeMessageClock(String userIdParam){
        WsMessageDTO messageDO = new WsMessageDTO();
        messageDO.setNeedBroadcast(false);   // 是否广播发送
        messageDO.setOnlyOneClientInSameKey(false); // 相同 sessionKey 的客户端只推送一次操作




        // 获取待发送的 sessionKeys
        Collection<Object> sessionKeys  =  adminUserApi.getSessionKeys().getData();
//        Collection<Object> sessionKeys  = webSocketSessionStore.getSessionKeys();
        long count = 0;
        for (Object sessionKey : sessionKeys) {
            UserAnnouncementQO userAnnouncementQO = new UserAnnouncementQO();
            String key = sessionKey.toString();
            if(key.contains("_")){
                    String userId = key.substring(key.indexOf("_")+1 , key.length() );
                     String tenantId = key.substring(0 , key.indexOf("_")  );
                TenantContextHolder.setTenantId(Long.valueOf(tenantId));
                log.info(tenantId + " sessionKeys, messageDo: {}", messageDO);
                         if(StringUtils.isNoneBlank(userIdParam) && userIdParam.equals(userId)){
                             userAnnouncementQO.setUserId(Long.valueOf(userId));
                             messageDO.setMessageText( JSONObject.toJSONString( getRemind(userAnnouncementQO)));
                             List<Object> list = new ArrayList<>();
                             list.add(sessionKey);
                             messageDO.setSessionKeys(list);
                             adminUserApi.distribute(messageDO);
//                             messageDistributor.distribute(messageDO);
                         }else{
                             userAnnouncementQO.setUserId(Long.valueOf(userId));
                             messageDO.setMessageText( JSONObject.toJSONString( getRemind(userAnnouncementQO)));
                             List<Object> list = new ArrayList<>();
                             list.add(sessionKey);
                             messageDO.setSessionKeys(list);
                             adminUserApi.distribute(messageDO);
//                             messageDistributor.distribute(messageDO);
                         }


                count++;
            }


        }
        return count;
    }

    @Override
    public List<AnnouncementDTO> getAnnouncementsAndNotices(UserAnnouncementQO userAnnouncementQO) {
    String sql =    " SELECT                                        " +
                        "   na.`title` AS title,                    " +
                        "   na.`content` AS content,                " +
                        "   na.`content_display` AS contentDisplay  " +
                        " FROM                                      " +
                        "   `notify_user_announcement` nua          " +
                        "   INNER JOIN `notify_announcement` na     " +
                        "     ON nua.`announcement_id` = na.`id`    " +
                        " WHERE nua.`user_id` = " + userAnnouncementQO.getUserId()       +
                        "   AND nua.`rec_deleted` = 0               " +
                        "   AND nua.`deleted` = 0                   " +
                        "   AND nua.`state` = 0                     " +
                        "   AND na.`deleted` = 0                    " +
                        "   AND na.`type` IN (1, 4)                 " +
                        "   AND na.`status` = 1                     " +
                        " ORDER BY nua.`create_time` DESC           " +
                        " LIMIT 4                                   ";
      return   baseMapper.getAnnouncementsAndNotices(sql);
    }


}
